//package com.ophiux.common.data.aspect;
//
//import cn.hutool.extra.servlet.ServletUtil;
//import cn.hutool.json.JSONUtil;
//import com.baomidou.mybatisplus.core.toolkit.Assert;
//import com.ophiux.common.data.annotation.RepeatSubmit;
//import org.aspectj.lang.ProceedingJoinPoint;
//import org.aspectj.lang.annotation.Around;
//import org.aspectj.lang.annotation.Aspect;
//import org.aspectj.lang.annotation.Pointcut;
//import org.aspectj.lang.reflect.MethodSignature;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.data.redis.core.script.DigestUtils;
//import org.springframework.web.context.request.RequestContextHolder;
//import org.springframework.web.context.request.ServletRequestAttributes;
//
//import javax.servlet.http.HttpServletRequest;
//import java.lang.reflect.Method;
//import java.util.Objects;
//import java.util.concurrent.TimeUnit;
//
///**
// * @desc: 防止重复操作切面（处理切面注解）
// * @author: hhl
// * @date：2023/3/1 14:45
// */
//@Aspect
//public class RepeatSubmitAspect {
//
//	private String PREVENT_DUPLICATION_PREFIX = "REPEAT_SUBMIT_PREFIX:";
//
//	@Autowired
//	private RedisTemplate redisTemplate;
//
//	/**
//	 * 定义切点
//	 */
//	@Pointcut("@annotation(com.ophiux.common.data.annotation.RepeatSubmit)")
//	public void repeatSubmit() {
//	}
//
//	/**
//	 * 环绕通知 （可以控制目标方法前中后期执行操作，目标方法执行前后分别执行一些代码）
//	 *
//	 * @param joinPoint
//	 * @return
//	 */
//	@Around("repeatSubmit()")
//	public Object before(ProceedingJoinPoint joinPoint) throws Exception {
//		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//		HttpServletRequest request = attributes.getRequest();
//		Assert.notNull(request, "request cannot be null.");
//
//		//获取执行方法
//		Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//		//获取防重复提交注解
//		RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
//		String ip = ServletUtil.getClientIP(request);
//		//目标类、方法
//		String className = method.getDeclaringClass().getName();
//		String name = method.getName();
//		String ipKey = String.format("%s#%s",className,name);
//		int hashCode = Math.abs(ipKey.hashCode());
//		String key = String.format("%s_%d",ip,hashCode);
//
//		// 获取token以及方法标记，生成redisKey和redisValue
////		String token = request.getParameter(CommonConstants.TOKEN);
//		String redisKey = PREVENT_DUPLICATION_PREFIX.concat(key);
//		String redisValue = redisKey.concat("repeat submit");
//
//		if (!redisTemplate.hasKey(redisKey)) {
//			//设置防重复操作限时标记（前置通知）
//			redisTemplate.opsForValue().set(redisKey, redisValue, annotation.value(), TimeUnit.SECONDS);
//			try {
//				//正常执行方法并返回
//				//ProceedingJoinPoint类型参数可以决定是否执行目标方法，且环绕通知必须要有返回值，返回值即为目标方法的返回值
//				return joinPoint.proceed();
//			} catch (Throwable throwable) {
//				//确保方法执行异常实时释放限时标记(异常后置通知)
//				redisTemplate.delete(redisKey);
//				throw new RuntimeException(throwable);
//			}
//		} else {
//			throw new RuntimeException("请勿重复提交");
//		}
//	}
//
//	/**
//	 * 生成方法标记：采用数字签名算法SHA1对方法签名字符串加签
//	 *
//	 * @param method
//	 * @param args
//	 * @return
//	 */
//	private String getMethodSign(Method method, Object... args) {
//		StringBuilder sb = new StringBuilder(method.toString());
//		for (Object arg : args) {
//			sb.append(toString(arg));
//		}
//		return DigestUtils.sha1DigestAsHex(sb.toString());
//	}
//
//	private String toString(Object arg) {
//		if (Objects.isNull(arg)) {
//			return "null";
//		}
//		if (arg instanceof Number) {
//			return arg.toString();
//		}
//		return JSONUtil.toJsonStr(arg);
//	}
//}